home *** CD-ROM | disk | FTP | other *** search
/ PCGUIA 127 / PC Guia 127.iso / Software / Produtividade / OpenOffice.org 2.0.1 / openofficeorg4.cab / test_weakref.py < prev    next >
Text File  |  2005-11-19  |  33KB  |  943 lines

  1. import gc
  2. import sys
  3. import unittest
  4. import UserList
  5. import weakref
  6.  
  7. from test import test_support
  8. from sets import Set
  9.  
  10.  
  11. class C:
  12.     def method(self):
  13.         pass
  14.  
  15.  
  16. class Callable:
  17.     bar = None
  18.  
  19.     def __call__(self, x):
  20.         self.bar = x
  21.  
  22.  
  23. def create_function():
  24.     def f(): pass
  25.     return f
  26.  
  27. def create_bound_method():
  28.     return C().method
  29.  
  30. def create_unbound_method():
  31.     return C.method
  32.  
  33.  
  34. class TestBase(unittest.TestCase):
  35.  
  36.     def setUp(self):
  37.         self.cbcalled = 0
  38.  
  39.     def callback(self, ref):
  40.         self.cbcalled += 1
  41.  
  42.  
  43. class ReferencesTestCase(TestBase):
  44.  
  45.     def test_basic_ref(self):
  46.         self.check_basic_ref(C)
  47.         self.check_basic_ref(create_function)
  48.         self.check_basic_ref(create_bound_method)
  49.         self.check_basic_ref(create_unbound_method)
  50.  
  51.         # Just make sure the tp_repr handler doesn't raise an exception.
  52.         # Live reference:
  53.         o = C()
  54.         wr = weakref.ref(o)
  55.         `wr`
  56.         # Dead reference:
  57.         del o
  58.         `wr`
  59.  
  60.     def test_basic_callback(self):
  61.         self.check_basic_callback(C)
  62.         self.check_basic_callback(create_function)
  63.         self.check_basic_callback(create_bound_method)
  64.         self.check_basic_callback(create_unbound_method)
  65.  
  66.     def test_multiple_callbacks(self):
  67.         o = C()
  68.         ref1 = weakref.ref(o, self.callback)
  69.         ref2 = weakref.ref(o, self.callback)
  70.         del o
  71.         self.assert_(ref1() is None,
  72.                      "expected reference to be invalidated")
  73.         self.assert_(ref2() is None,
  74.                      "expected reference to be invalidated")
  75.         self.assert_(self.cbcalled == 2,
  76.                      "callback not called the right number of times")
  77.  
  78.     def test_multiple_selfref_callbacks(self):
  79.         # Make sure all references are invalidated before callbacks are called
  80.         #
  81.         # What's important here is that we're using the first
  82.         # reference in the callback invoked on the second reference
  83.         # (the most recently created ref is cleaned up first).  This
  84.         # tests that all references to the object are invalidated
  85.         # before any of the callbacks are invoked, so that we only
  86.         # have one invocation of _weakref.c:cleanup_helper() active
  87.         # for a particular object at a time.
  88.         #
  89.         def callback(object, self=self):
  90.             self.ref()
  91.         c = C()
  92.         self.ref = weakref.ref(c, callback)
  93.         ref1 = weakref.ref(c, callback)
  94.         del c
  95.  
  96.     def test_proxy_ref(self):
  97.         o = C()
  98.         o.bar = 1
  99.         ref1 = weakref.proxy(o, self.callback)
  100.         ref2 = weakref.proxy(o, self.callback)
  101.         del o
  102.  
  103.         def check(proxy):
  104.             proxy.bar
  105.  
  106.         self.assertRaises(weakref.ReferenceError, check, ref1)
  107.         self.assertRaises(weakref.ReferenceError, check, ref2)
  108.         self.assert_(self.cbcalled == 2)
  109.  
  110.     def check_basic_ref(self, factory):
  111.         o = factory()
  112.         ref = weakref.ref(o)
  113.         self.assert_(ref() is not None,
  114.                      "weak reference to live object should be live")
  115.         o2 = ref()
  116.         self.assert_(o is o2,
  117.                      "<ref>() should return original object if live")
  118.  
  119.     def check_basic_callback(self, factory):
  120.         self.cbcalled = 0
  121.         o = factory()
  122.         ref = weakref.ref(o, self.callback)
  123.         del o
  124.         self.assert_(self.cbcalled == 1,
  125.                      "callback did not properly set 'cbcalled'")
  126.         self.assert_(ref() is None,
  127.                      "ref2 should be dead after deleting object reference")
  128.  
  129.     def test_ref_reuse(self):
  130.         o = C()
  131.         ref1 = weakref.ref(o)
  132.         # create a proxy to make sure that there's an intervening creation
  133.         # between these two; it should make no difference
  134.         proxy = weakref.proxy(o)
  135.         ref2 = weakref.ref(o)
  136.         self.assert_(ref1 is ref2,
  137.                      "reference object w/out callback should be re-used")
  138.  
  139.         o = C()
  140.         proxy = weakref.proxy(o)
  141.         ref1 = weakref.ref(o)
  142.         ref2 = weakref.ref(o)
  143.         self.assert_(ref1 is ref2,
  144.                      "reference object w/out callback should be re-used")
  145.         self.assert_(weakref.getweakrefcount(o) == 2,
  146.                      "wrong weak ref count for object")
  147.         del proxy
  148.         self.assert_(weakref.getweakrefcount(o) == 1,
  149.                      "wrong weak ref count for object after deleting proxy")
  150.  
  151.     def test_proxy_reuse(self):
  152.         o = C()
  153.         proxy1 = weakref.proxy(o)
  154.         ref = weakref.ref(o)
  155.         proxy2 = weakref.proxy(o)
  156.         self.assert_(proxy1 is proxy2,
  157.                      "proxy object w/out callback should have been re-used")
  158.  
  159.     def test_basic_proxy(self):
  160.         o = C()
  161.         self.check_proxy(o, weakref.proxy(o))
  162.  
  163.         L = UserList.UserList()
  164.         p = weakref.proxy(L)
  165.         self.failIf(p, "proxy for empty UserList should be false")
  166.         p.append(12)
  167.         self.assertEqual(len(L), 1)
  168.         self.failUnless(p, "proxy for non-empty UserList should be true")
  169.         p[:] = [2, 3]
  170.         self.assertEqual(len(L), 2)
  171.         self.assertEqual(len(p), 2)
  172.         self.failUnless(3 in p,
  173.                         "proxy didn't support __contains__() properly")
  174.         p[1] = 5
  175.         self.assertEqual(L[1], 5)
  176.         self.assertEqual(p[1], 5)
  177.         L2 = UserList.UserList(L)
  178.         p2 = weakref.proxy(L2)
  179.         self.assertEqual(p, p2)
  180.         ## self.assertEqual(`L2`, `p2`)
  181.         L3 = UserList.UserList(range(10))
  182.         p3 = weakref.proxy(L3)
  183.         self.assertEqual(L3[:], p3[:])
  184.         self.assertEqual(L3[5:], p3[5:])
  185.         self.assertEqual(L3[:5], p3[:5])
  186.         self.assertEqual(L3[2:5], p3[2:5])
  187.  
  188.     # The PyWeakref_* C API is documented as allowing either NULL or
  189.     # None as the value for the callback, where either means "no
  190.     # callback".  The "no callback" ref and proxy objects are supposed
  191.     # to be shared so long as they exist by all callers so long as
  192.     # they are active.  In Python 2.3.3 and earlier, this guaranttee
  193.     # was not honored, and was broken in different ways for
  194.     # PyWeakref_NewRef() and PyWeakref_NewProxy().  (Two tests.)
  195.  
  196.     def test_shared_ref_without_callback(self):
  197.         self.check_shared_without_callback(weakref.ref)
  198.  
  199.     def test_shared_proxy_without_callback(self):
  200.         self.check_shared_without_callback(weakref.proxy)
  201.  
  202.     def check_shared_without_callback(self, makeref):
  203.         o = Object(1)
  204.         p1 = makeref(o, None)
  205.         p2 = makeref(o, None)
  206.         self.assert_(p1 is p2, "both callbacks were None in the C API")
  207.         del p1, p2
  208.         p1 = makeref(o)
  209.         p2 = makeref(o, None)
  210.         self.assert_(p1 is p2, "callbacks were NULL, None in the C API")
  211.         del p1, p2
  212.         p1 = makeref(o)
  213.         p2 = makeref(o)
  214.         self.assert_(p1 is p2, "both callbacks were NULL in the C API")
  215.         del p1, p2
  216.         p1 = makeref(o, None)
  217.         p2 = makeref(o)
  218.         self.assert_(p1 is p2, "callbacks were None, NULL in the C API")
  219.  
  220.     def test_callable_proxy(self):
  221.         o = Callable()
  222.         ref1 = weakref.proxy(o)
  223.  
  224.         self.check_proxy(o, ref1)
  225.  
  226.         self.assert_(type(ref1) is weakref.CallableProxyType,
  227.                      "proxy is not of callable type")
  228.         ref1('twinkies!')
  229.         self.assert_(o.bar == 'twinkies!',
  230.                      "call through proxy not passed through to original")
  231.         ref1(x='Splat.')
  232.         self.assert_(o.bar == 'Splat.',
  233.                      "call through proxy not passed through to original")
  234.  
  235.         # expect due to too few args
  236.         self.assertRaises(TypeError, ref1)
  237.  
  238.         # expect due to too many args
  239.         self.assertRaises(TypeError, ref1, 1, 2, 3)
  240.  
  241.     def check_proxy(self, o, proxy):
  242.         o.foo = 1
  243.         self.assert_(proxy.foo == 1,
  244.                      "proxy does not reflect attribute addition")
  245.         o.foo = 2
  246.         self.assert_(proxy.foo == 2,
  247.                      "proxy does not reflect attribute modification")
  248.         del o.foo
  249.         self.assert_(not hasattr(proxy, 'foo'),
  250.                      "proxy does not reflect attribute removal")
  251.  
  252.         proxy.foo = 1
  253.         self.assert_(o.foo == 1,
  254.                      "object does not reflect attribute addition via proxy")
  255.         proxy.foo = 2
  256.         self.assert_(
  257.             o.foo == 2,
  258.             "object does not reflect attribute modification via proxy")
  259.         del proxy.foo
  260.         self.assert_(not hasattr(o, 'foo'),
  261.                      "object does not reflect attribute removal via proxy")
  262.  
  263.     def test_proxy_deletion(self):
  264.         # Test clearing of SF bug #762891
  265.         class Foo:
  266.             result = None
  267.             def __delitem__(self, accessor):
  268.                 self.result = accessor
  269.         g = Foo()
  270.         f = weakref.proxy(g)
  271.         del f[0]
  272.         self.assertEqual(f.result, 0)
  273.  
  274.     def test_getweakrefcount(self):
  275.         o = C()
  276.         ref1 = weakref.ref(o)
  277.         ref2 = weakref.ref(o, self.callback)
  278.         self.assert_(weakref.getweakrefcount(o) == 2,
  279.                      "got wrong number of weak reference objects")
  280.  
  281.         proxy1 = weakref.proxy(o)
  282.         proxy2 = weakref.proxy(o, self.callback)
  283.         self.assert_(weakref.getweakrefcount(o) == 4,
  284.                      "got wrong number of weak reference objects")
  285.  
  286.         del ref1, ref2, proxy1, proxy2
  287.         self.assert_(weakref.getweakrefcount(o) == 0,
  288.                      "weak reference objects not unlinked from"
  289.                      " referent when discarded.")
  290.  
  291.         # assumes ints do not support weakrefs
  292.         self.assert_(weakref.getweakrefcount(1) == 0,
  293.                      "got wrong number of weak reference objects for int")
  294.  
  295.     def test_getweakrefs(self):
  296.         o = C()
  297.         ref1 = weakref.ref(o, self.callback)
  298.         ref2 = weakref.ref(o, self.callback)
  299.         del ref1
  300.         self.assert_(weakref.getweakrefs(o) == [ref2],
  301.                      "list of refs does not match")
  302.  
  303.         o = C()
  304.         ref1 = weakref.ref(o, self.callback)
  305.         ref2 = weakref.ref(o, self.callback)
  306.         del ref2
  307.         self.assert_(weakref.getweakrefs(o) == [ref1],
  308.                      "list of refs does not match")
  309.  
  310.         del ref1
  311.         self.assert_(weakref.getweakrefs(o) == [],
  312.                      "list of refs not cleared")
  313.  
  314.         # assumes ints do not support weakrefs
  315.         self.assert_(weakref.getweakrefs(1) == [],
  316.                      "list of refs does not match for int")
  317.  
  318.     def test_newstyle_number_ops(self):
  319.         class F(float):
  320.             pass
  321.         f = F(2.0)
  322.         p = weakref.proxy(f)
  323.         self.assert_(p + 1.0 == 3.0)
  324.         self.assert_(1.0 + p == 3.0)  # this used to SEGV
  325.  
  326.     def test_callbacks_protected(self):
  327.         # Callbacks protected from already-set exceptions?
  328.         # Regression test for SF bug #478534.
  329.         class BogusError(Exception):
  330.             pass
  331.         data = {}
  332.         def remove(k):
  333.             del data[k]
  334.         def encapsulate():
  335.             f = lambda : ()
  336.             data[weakref.ref(f, remove)] = None
  337.             raise BogusError
  338.         try:
  339.             encapsulate()
  340.         except BogusError:
  341.             pass
  342.         else:
  343.             self.fail("exception not properly restored")
  344.         try:
  345.             encapsulate()
  346.         except BogusError:
  347.             pass
  348.         else:
  349.             self.fail("exception not properly restored")
  350.  
  351.     def test_sf_bug_840829(self):
  352.         # "weakref callbacks and gc corrupt memory"
  353.         # subtype_dealloc erroneously exposed a new-style instance
  354.         # already in the process of getting deallocated to gc,
  355.         # causing double-deallocation if the instance had a weakref
  356.         # callback that triggered gc.
  357.         # If the bug exists, there probably won't be an obvious symptom
  358.         # in a release build.  In a debug build, a segfault will occur
  359.         # when the second attempt to remove the instance from the "list
  360.         # of all objects" occurs.
  361.  
  362.         import gc
  363.  
  364.         class C(object):
  365.             pass
  366.  
  367.         c = C()
  368.         wr = weakref.ref(c, lambda ignore: gc.collect())
  369.         del c
  370.  
  371.         # There endeth the first part.  It gets worse.
  372.         del wr
  373.  
  374.         c1 = C()
  375.         c1.i = C()
  376.         wr = weakref.ref(c1.i, lambda ignore: gc.collect())
  377.  
  378.         c2 = C()
  379.         c2.c1 = c1
  380.         del c1  # still alive because c2 points to it
  381.  
  382.         # Now when subtype_dealloc gets called on c2, it's not enough just
  383.         # that c2 is immune from gc while the weakref callbacks associated
  384.         # with c2 execute (there are none in this 2nd half of the test, btw).
  385.         # subtype_dealloc goes on to call the base classes' deallocs too,
  386.         # so any gc triggered by weakref callbacks associated with anything
  387.         # torn down by a base class dealloc can also trigger double
  388.         # deallocation of c2.
  389.         del c2
  390.  
  391.     def test_callback_in_cycle_1(self):
  392.         import gc
  393.  
  394.         class J(object):
  395.             pass
  396.  
  397.         class II(object):
  398.             def acallback(self, ignore):
  399.                 self.J
  400.  
  401.         I = II()
  402.         I.J = J
  403.         I.wr = weakref.ref(J, I.acallback)
  404.  
  405.         # Now J and II are each in a self-cycle (as all new-style class
  406.         # objects are, since their __mro__ points back to them).  I holds
  407.         # both a weak reference (I.wr) and a strong reference (I.J) to class
  408.         # J.  I is also in a cycle (I.wr points to a weakref that references
  409.         # I.acallback).  When we del these three, they all become trash, but
  410.         # the cycles prevent any of them from getting cleaned up immediately.
  411.         # Instead they have to wait for cyclic gc to deduce that they're
  412.         # trash.
  413.         #
  414.         # gc used to call tp_clear on all of them, and the order in which
  415.         # it does that is pretty accidental.  The exact order in which we
  416.         # built up these things manages to provoke gc into running tp_clear
  417.         # in just the right order (I last).  Calling tp_clear on II leaves
  418.         # behind an insane class object (its __mro__ becomes NULL).  Calling
  419.         # tp_clear on J breaks its self-cycle, but J doesn't get deleted
  420.         # just then because of the strong reference from I.J.  Calling
  421.         # tp_clear on I starts to clear I's __dict__, and just happens to
  422.         # clear I.J first -- I.wr is still intact.  That removes the last
  423.         # reference to J, which triggers the weakref callback.  The callback
  424.         # tries to do "self.J", and instances of new-style classes look up
  425.         # attributes ("J") in the class dict first.  The class (II) wants to
  426.         # search II.__mro__, but that's NULL.   The result was a segfault in
  427.         # a release build, and an assert failure in a debug build.
  428.         del I, J, II
  429.         gc.collect()
  430.  
  431.     def test_callback_in_cycle_2(self):
  432.         import gc
  433.  
  434.         # This is just like test_callback_in_cycle_1, except that II is an
  435.         # old-style class.  The symptom is different then:  an instance of an
  436.         # old-style class looks in its own __dict__ first.  'J' happens to
  437.         # get cleared from I.__dict__ before 'wr', and 'J' was never in II's
  438.         # __dict__, so the attribute isn't found.  The difference is that
  439.         # the old-style II doesn't have a NULL __mro__ (it doesn't have any
  440.         # __mro__), so no segfault occurs.  Instead it got:
  441.         #    test_callback_in_cycle_2 (__main__.ReferencesTestCase) ...
  442.         #    Exception exceptions.AttributeError:
  443.         #   "II instance has no attribute 'J'" in <bound method II.acallback
  444.         #       of <?.II instance at 0x00B9B4B8>> ignored
  445.  
  446.         class J(object):
  447.             pass
  448.  
  449.         class II:
  450.             def acallback(self, ignore):
  451.                 self.J
  452.  
  453.         I = II()
  454.         I.J = J
  455.         I.wr = weakref.ref(J, I.acallback)
  456.  
  457.         del I, J, II
  458.         gc.collect()
  459.  
  460.     def test_callback_in_cycle_3(self):
  461.         import gc
  462.  
  463.         # This one broke the first patch that fixed the last two.  In this
  464.         # case, the objects reachable from the callback aren't also reachable
  465.         # from the object (c1) *triggering* the callback:  you can get to
  466.         # c1 from c2, but not vice-versa.  The result was that c2's __dict__
  467.         # got tp_clear'ed by the time the c2.cb callback got invoked.
  468.  
  469.         class C:
  470.             def cb(self, ignore):
  471.                 self.me
  472.                 self.c1
  473.                 self.wr
  474.  
  475.         c1, c2 = C(), C()
  476.  
  477.         c2.me = c2
  478.         c2.c1 = c1
  479.         c2.wr = weakref.ref(c1, c2.cb)
  480.  
  481.         del c1, c2
  482.         gc.collect()
  483.  
  484.     def test_callback_in_cycle_4(self):
  485.         import gc
  486.  
  487.         # Like test_callback_in_cycle_3, except c2 and c1 have different
  488.         # classes.  c2's class (C) isn't reachable from c1 then, so protecting
  489.         # objects reachable from the dying object (c1) isn't enough to stop
  490.         # c2's class (C) from getting tp_clear'ed before c2.cb is invoked.
  491.         # The result was a segfault (C.__mro__ was NULL when the callback
  492.         # tried to look up self.me).
  493.  
  494.         class C(object):
  495.             def cb(self, ignore):
  496.                 self.me
  497.                 self.c1
  498.                 self.wr
  499.  
  500.         class D:
  501.             pass
  502.  
  503.         c1, c2 = D(), C()
  504.  
  505.         c2.me = c2
  506.         c2.c1 = c1
  507.         c2.wr = weakref.ref(c1, c2.cb)
  508.  
  509.         del c1, c2, C, D
  510.         gc.collect()
  511.  
  512.     def test_callback_in_cycle_resurrection(self):
  513.         import gc
  514.  
  515.         # Do something nasty in a weakref callback:  resurrect objects
  516.         # from dead cycles.  For this to be attempted, the weakref and
  517.         # its callback must also be part of the cyclic trash (else the
  518.         # objects reachable via the callback couldn't be in cyclic trash
  519.         # to begin with -- the callback would act like an external root).
  520.         # But gc clears trash weakrefs with callbacks early now, which
  521.         # disables the callbacks, so the callbacks shouldn't get called
  522.         # at all (and so nothing actually gets resurrected).
  523.  
  524.         alist = []
  525.         class C(object):
  526.             def __init__(self, value):
  527.                 self.attribute = value
  528.  
  529.             def acallback(self, ignore):
  530.                 alist.append(self.c)
  531.  
  532.         c1, c2 = C(1), C(2)
  533.         c1.c = c2
  534.         c2.c = c1
  535.         c1.wr = weakref.ref(c2, c1.acallback)
  536.         c2.wr = weakref.ref(c1, c2.acallback)
  537.  
  538.         def C_went_away(ignore):
  539.             alist.append("C went away")
  540.         wr = weakref.ref(C, C_went_away)
  541.  
  542.         del c1, c2, C   # make them all trash
  543.         self.assertEqual(alist, [])  # del isn't enough to reclaim anything
  544.  
  545.         gc.collect()
  546.         # c1.wr and c2.wr were part of the cyclic trash, so should have
  547.         # been cleared without their callbacks executing.  OTOH, the weakref
  548.         # to C is bound to a function local (wr), and wasn't trash, so that
  549.         # callback should have been invoked when C went away.
  550.         self.assertEqual(alist, ["C went away"])
  551.         # The remaining weakref should be dead now (its callback ran).
  552.         self.assertEqual(wr(), None)
  553.  
  554.         del alist[:]
  555.         gc.collect()
  556.         self.assertEqual(alist, [])
  557.  
  558.     def test_callbacks_on_callback(self):
  559.         import gc
  560.  
  561.         # Set up weakref callbacks *on* weakref callbacks.
  562.         alist = []
  563.         def safe_callback(ignore):
  564.             alist.append("safe_callback called")
  565.  
  566.         class C(object):
  567.             def cb(self, ignore):
  568.                 alist.append("cb called")
  569.  
  570.         c, d = C(), C()
  571.         c.other = d
  572.         d.other = c
  573.         callback = c.cb
  574.         c.wr = weakref.ref(d, callback)     # this won't trigger
  575.         d.wr = weakref.ref(callback, d.cb)  # ditto
  576.         external_wr = weakref.ref(callback, safe_callback)  # but this will
  577.         self.assert_(external_wr() is callback)
  578.  
  579.         # The weakrefs attached to c and d should get cleared, so that
  580.         # C.cb is never called.  But external_wr isn't part of the cyclic
  581.         # trash, and no cyclic trash is reachable from it, so safe_callback
  582.         # should get invoked when the bound method object callback (c.cb)
  583.         # -- which is itself a callback, and also part of the cyclic trash --
  584.         # gets reclaimed at the end of gc.
  585.  
  586.         del callback, c, d, C
  587.         self.assertEqual(alist, [])  # del isn't enough to clean up cycles
  588.         gc.collect()
  589.         self.assertEqual(alist, ["safe_callback called"])
  590.         self.assertEqual(external_wr(), None)
  591.  
  592.         del alist[:]
  593.         gc.collect()
  594.         self.assertEqual(alist, [])
  595.  
  596.     def test_gc_during_ref_creation(self):
  597.         self.check_gc_during_creation(weakref.ref)
  598.  
  599.     def test_gc_during_proxy_creation(self):
  600.         self.check_gc_during_creation(weakref.proxy)
  601.  
  602.     def check_gc_during_creation(self, makeref):
  603.         thresholds = gc.get_threshold()
  604.         gc.set_threshold(1, 1, 1)
  605.         gc.collect()
  606.         class A:
  607.             pass
  608.  
  609.         def callback(*args):
  610.             pass
  611.  
  612.         referenced = A()
  613.  
  614.         a = A()
  615.         a.a = a
  616.         a.wr = makeref(referenced)
  617.  
  618.         try:
  619.             # now make sure the object and the ref get labeled as
  620.             # cyclic trash:
  621.             a = A()
  622.             a.wrc = weakref.ref(referenced, callback)
  623.  
  624.         finally:
  625.             gc.set_threshold(*thresholds)
  626.  
  627. class Object:
  628.     def __init__(self, arg):
  629.         self.arg = arg
  630.     def __repr__(self):
  631.         return "<Object %r>" % self.arg
  632.  
  633.  
  634. class MappingTestCase(TestBase):
  635.  
  636.     COUNT = 10
  637.  
  638.     def test_weak_values(self):
  639.         #
  640.         #  This exercises d.copy(), d.items(), d[], del d[], len(d).
  641.         #
  642.         dict, objects = self.make_weak_valued_dict()
  643.         for o in objects:
  644.             self.assert_(weakref.getweakrefcount(o) == 1,
  645.                          "wrong number of weak references to %r!" % o)
  646.             self.assert_(o is dict[o.arg],
  647.                          "wrong object returned by weak dict!")
  648.         items1 = dict.items()
  649.         items2 = dict.copy().items()
  650.         items1.sort()
  651.         items2.sort()
  652.         self.assert_(items1 == items2,
  653.                      "cloning of weak-valued dictionary did not work!")
  654.         del items1, items2
  655.         self.assert_(len(dict) == self.COUNT)
  656.         del objects[0]
  657.         self.assert_(len(dict) == (self.COUNT - 1),
  658.                      "deleting object did not cause dictionary update")
  659.         del objects, o
  660.         self.assert_(len(dict) == 0,
  661.                      "deleting the values did not clear the dictionary")
  662.         # regression on SF bug #447152:
  663.         dict = weakref.WeakValueDictionary()
  664.         self.assertRaises(KeyError, dict.__getitem__, 1)
  665.         dict[2] = C()
  666.         self.assertRaises(KeyError, dict.__getitem__, 2)
  667.  
  668.     def test_weak_keys(self):
  669.         #
  670.         #  This exercises d.copy(), d.items(), d[] = v, d[], del d[],
  671.         #  len(d), d.has_key().
  672.         #
  673.         dict, objects = self.make_weak_keyed_dict()
  674.         for o in objects:
  675.             self.assert_(weakref.getweakrefcount(o) == 1,
  676.                          "wrong number of weak references to %r!" % o)
  677.             self.assert_(o.arg is dict[o],
  678.                          "wrong object returned by weak dict!")
  679.         items1 = dict.items()
  680.         items2 = dict.copy().items()
  681.         self.assert_(Set(items1) == Set(items2),
  682.                      "cloning of weak-keyed dictionary did not work!")
  683.         del items1, items2
  684.         self.assert_(len(dict) == self.COUNT)
  685.         del objects[0]
  686.         self.assert_(len(dict) == (self.COUNT - 1),
  687.                      "deleting object did not cause dictionary update")
  688.         del objects, o
  689.         self.assert_(len(dict) == 0,
  690.                      "deleting the keys did not clear the dictionary")
  691.         o = Object(42)
  692.         dict[o] = "What is the meaning of the universe?"
  693.         self.assert_(dict.has_key(o))
  694.         self.assert_(not dict.has_key(34))
  695.  
  696.     def test_weak_keyed_iters(self):
  697.         dict, objects = self.make_weak_keyed_dict()
  698.         self.check_iters(dict)
  699.  
  700.     def test_weak_valued_iters(self):
  701.         dict, objects = self.make_weak_valued_dict()
  702.         self.check_iters(dict)
  703.  
  704.     def check_iters(self, dict):
  705.         # item iterator:
  706.         items = dict.items()
  707.         for item in dict.iteritems():
  708.             items.remove(item)
  709.         self.assert_(len(items) == 0, "iteritems() did not touch all items")
  710.  
  711.         # key iterator, via __iter__():
  712.         keys = dict.keys()
  713.         for k in dict:
  714.             keys.remove(k)
  715.         self.assert_(len(keys) == 0, "__iter__() did not touch all keys")
  716.  
  717.         # key iterator, via iterkeys():
  718.         keys = dict.keys()
  719.         for k in dict.iterkeys():
  720.             keys.remove(k)
  721.         self.assert_(len(keys) == 0, "iterkeys() did not touch all keys")
  722.  
  723.         # value iterator:
  724.         values = dict.values()
  725.         for v in dict.itervalues():
  726.             values.remove(v)
  727.         self.assert_(len(values) == 0,
  728.                      "itervalues() did not touch all values")
  729.  
  730.     def test_make_weak_keyed_dict_from_dict(self):
  731.         o = Object(3)
  732.         dict = weakref.WeakKeyDictionary({o:364})
  733.         self.assert_(dict[o] == 364)
  734.  
  735.     def test_make_weak_keyed_dict_from_weak_keyed_dict(self):
  736.         o = Object(3)
  737.         dict = weakref.WeakKeyDictionary({o:364})
  738.         dict2 = weakref.WeakKeyDictionary(dict)
  739.         self.assert_(dict[o] == 364)
  740.  
  741.     def make_weak_keyed_dict(self):
  742.         dict = weakref.WeakKeyDictionary()
  743.         objects = map(Object, range(self.COUNT))
  744.         for o in objects:
  745.             dict[o] = o.arg
  746.         return dict, objects
  747.  
  748.     def make_weak_valued_dict(self):
  749.         dict = weakref.WeakValueDictionary()
  750.         objects = map(Object, range(self.COUNT))
  751.         for o in objects:
  752.             dict[o.arg] = o
  753.         return dict, objects
  754.  
  755.     def check_popitem(self, klass, key1, value1, key2, value2):
  756.         weakdict = klass()
  757.         weakdict[key1] = value1
  758.         weakdict[key2] = value2
  759.         self.assert_(len(weakdict) == 2)
  760.         k, v = weakdict.popitem()
  761.         self.assert_(len(weakdict) == 1)
  762.         if k is key1:
  763.             self.assert_(v is value1)
  764.         else:
  765.             self.assert_(v is value2)
  766.         k, v = weakdict.popitem()
  767.         self.assert_(len(weakdict) == 0)
  768.         if k is key1:
  769.             self.assert_(v is value1)
  770.         else:
  771.             self.assert_(v is value2)
  772.  
  773.     def test_weak_valued_dict_popitem(self):
  774.         self.check_popitem(weakref.WeakValueDictionary,
  775.                            "key1", C(), "key2", C())
  776.  
  777.     def test_weak_keyed_dict_popitem(self):
  778.         self.check_popitem(weakref.WeakKeyDictionary,
  779.                            C(), "value 1", C(), "value 2")
  780.  
  781.     def check_setdefault(self, klass, key, value1, value2):
  782.         self.assert_(value1 is not value2,
  783.                      "invalid test"
  784.                      " -- value parameters must be distinct objects")
  785.         weakdict = klass()
  786.         o = weakdict.setdefault(key, value1)
  787.         self.assert_(o is value1)
  788.         self.assert_(weakdict.has_key(key))
  789.         self.assert_(weakdict.get(key) is value1)
  790.         self.assert_(weakdict[key] is value1)
  791.  
  792.         o = weakdict.setdefault(key, value2)
  793.         self.assert_(o is value1)
  794.         self.assert_(weakdict.has_key(key))
  795.         self.assert_(weakdict.get(key) is value1)
  796.         self.assert_(weakdict[key] is value1)
  797.  
  798.     def test_weak_valued_dict_setdefault(self):
  799.         self.check_setdefault(weakref.WeakValueDictionary,
  800.                               "key", C(), C())
  801.  
  802.     def test_weak_keyed_dict_setdefault(self):
  803.         self.check_setdefault(weakref.WeakKeyDictionary,
  804.                               C(), "value 1", "value 2")
  805.  
  806.     def check_update(self, klass, dict):
  807.         #
  808.         #  This exercises d.update(), len(d), d.keys(), d.has_key(),
  809.         #  d.get(), d[].
  810.         #
  811.         weakdict = klass()
  812.         weakdict.update(dict)
  813.         self.assert_(len(weakdict) == len(dict))
  814.         for k in weakdict.keys():
  815.             self.assert_(dict.has_key(k),
  816.                          "mysterious new key appeared in weak dict")
  817.             v = dict.get(k)
  818.             self.assert_(v is weakdict[k])
  819.             self.assert_(v is weakdict.get(k))
  820.         for k in dict.keys():
  821.             self.assert_(weakdict.has_key(k),
  822.                          "original key disappeared in weak dict")
  823.             v = dict[k]
  824.             self.assert_(v is weakdict[k])
  825.             self.assert_(v is weakdict.get(k))
  826.  
  827.     def test_weak_valued_dict_update(self):
  828.         self.check_update(weakref.WeakValueDictionary,
  829.                           {1: C(), 'a': C(), C(): C()})
  830.  
  831.     def test_weak_keyed_dict_update(self):
  832.         self.check_update(weakref.WeakKeyDictionary,
  833.                           {C(): 1, C(): 2, C(): 3})
  834.  
  835.     def test_weak_keyed_delitem(self):
  836.         d = weakref.WeakKeyDictionary()
  837.         o1 = Object('1')
  838.         o2 = Object('2')
  839.         d[o1] = 'something'
  840.         d[o2] = 'something'
  841.         self.assert_(len(d) == 2)
  842.         del d[o1]
  843.         self.assert_(len(d) == 1)
  844.         self.assert_(d.keys() == [o2])
  845.  
  846.     def test_weak_valued_delitem(self):
  847.         d = weakref.WeakValueDictionary()
  848.         o1 = Object('1')
  849.         o2 = Object('2')
  850.         d['something'] = o1
  851.         d['something else'] = o2
  852.         self.assert_(len(d) == 2)
  853.         del d['something']
  854.         self.assert_(len(d) == 1)
  855.         self.assert_(d.items() == [('something else', o2)])
  856.  
  857.     def test_weak_keyed_bad_delitem(self):
  858.         d = weakref.WeakKeyDictionary()
  859.         o = Object('1')
  860.         # An attempt to delete an object that isn't there should raise
  861.         # KeyError.  It didn't before 2.3.
  862.         self.assertRaises(KeyError, d.__delitem__, o)
  863.         self.assertRaises(KeyError, d.__getitem__, o)
  864.  
  865.         # If a key isn't of a weakly referencable type, __getitem__ and
  866.         # __setitem__ raise TypeError.  __delitem__ should too.
  867.         self.assertRaises(TypeError, d.__delitem__,  13)
  868.         self.assertRaises(TypeError, d.__getitem__,  13)
  869.         self.assertRaises(TypeError, d.__setitem__,  13, 13)
  870.  
  871.     def test_weak_keyed_cascading_deletes(self):
  872.         # SF bug 742860.  For some reason, before 2.3 __delitem__ iterated
  873.         # over the keys via self.data.iterkeys().  If things vanished from
  874.         # the dict during this (or got added), that caused a RuntimeError.
  875.  
  876.         d = weakref.WeakKeyDictionary()
  877.         mutate = False
  878.  
  879.         class C(object):
  880.             def __init__(self, i):
  881.                 self.value = i
  882.             def __hash__(self):
  883.                 return hash(self.value)
  884.             def __eq__(self, other):
  885.                 if mutate:
  886.                     # Side effect that mutates the dict, by removing the
  887.                     # last strong reference to a key.
  888.                     del objs[-1]
  889.                 return self.value == other.value
  890.  
  891.         objs = [C(i) for i in range(4)]
  892.         for o in objs:
  893.             d[o] = o.value
  894.         del o   # now the only strong references to keys are in objs
  895.         # Find the order in which iterkeys sees the keys.
  896.         objs = d.keys()
  897.         # Reverse it, so that the iteration implementation of __delitem__
  898.         # has to keep looping to find the first object we delete.
  899.         objs.reverse()
  900.  
  901.         # Turn on mutation in C.__eq__.  The first time thru the loop,
  902.         # under the iterkeys() business the first comparison will delete
  903.         # the last item iterkeys() would see, and that causes a
  904.         #     RuntimeError: dictionary changed size during iteration
  905.         # when the iterkeys() loop goes around to try comparing the next
  906.         # key.  After this was fixed, it just deletes the last object *our*
  907.         # "for o in obj" loop would have gotten to.
  908.         mutate = True
  909.         count = 0
  910.         for o in objs:
  911.             count += 1
  912.             del d[o]
  913.         self.assertEqual(len(d), 0)
  914.         self.assertEqual(count, 2)
  915.  
  916. from test_userdict import TestMappingProtocol
  917.  
  918. class WeakValueDictionaryTestCase(TestMappingProtocol):
  919.     """Check that WeakValueDictionary conforms to the mapping protocol"""
  920.     __ref = {"key1":Object(1), "key2":Object(2), "key3":Object(3)}
  921.     _tested_class = weakref.WeakValueDictionary
  922.     def _reference(self):
  923.         return self.__ref.copy()
  924.  
  925. class WeakKeyDictionaryTestCase(TestMappingProtocol):
  926.     """Check that WeakKeyDictionary conforms to the mapping protocol"""
  927.     __ref = {Object("key1"):1, Object("key2"):2, Object("key3"):3}
  928.     _tested_class = weakref.WeakKeyDictionary
  929.     def _reference(self):
  930.         return self.__ref.copy()
  931.  
  932. def test_main():
  933.     test_support.run_unittest(
  934.         ReferencesTestCase,
  935.         MappingTestCase,
  936.         WeakValueDictionaryTestCase,
  937.         WeakKeyDictionaryTestCase,
  938.         )
  939.  
  940.  
  941. if __name__ == "__main__":
  942.     test_main()
  943.